/*
 * $Id$
 *
 * Copyright (C) IUT Montreuil-University Paris 8, 2009-2010
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

package fr.univ_paris8.iut.linc.align;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataExactCardinality;
import org.semanticweb.owlapi.model.OWLDataMaxCardinality;
import org.semanticweb.owlapi.model.OWLDataMinCardinality;
import org.semanticweb.owlapi.model.OWLDataSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLInverseObjectPropertiesAxiom;
import org.semanticweb.owlapi.model.OWLObjectExactCardinality;
import org.semanticweb.owlapi.model.OWLObjectMaxCardinality;
import org.semanticweb.owlapi.model.OWLObjectMinCardinality;
import org.semanticweb.owlapi.model.OWLObjectPropertyExpression;
import org.semanticweb.owlapi.model.OWLObjectSomeValuesFrom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.util.OWLClassExpressionVisitorAdapter;





public class TransformOWLIntoGraph {
Graph gh = new Graph();

public Graph OWL_Graph (OWLOntology ontology){
Concept CSource,CTarget = null;
Edge e;

//Parcourir tous les concepts de l'ontologie
for (OWLClass cls : ontology.getClassesInSignature()) {
	CSource = new Concept (cls.toString());
	//Ajouter le concept à ListConcept s'il n'existe pas déja
	if (!(gh.ListConcept.contains(CSource)))
		 	gh.ListConcept.add(CSource);
	//Parcourir tous les super-classes du concept en question
	for (OWLClassExpression cl : cls.getSuperClasses(ontology)){
		 	
			if (!(cl.isAnonymous())){
		 		CTarget= new Concept (cl.toString());
		 		e = new Edge (CSource,CTarget,"SubClass", null);
		 		if (!(gh.ListEdge.contains(e)))
		 			gh.ListEdge.add(e);
		 	}
		 	else {
		 		
		 		if (cl.getClassesInSignature().size()<=1){
    				   	
    					Restriction(CSource,cl, ontology, "SuperClasses");
    					
    				}
    				
    			}
		 	
	 }
	//Parcourir toutes les sous-classes du concept en question
	for (OWLClassExpression cl : cls.getSubClasses(ontology)){
		if (!(cl.isAnonymous())){
			CTarget = new Concept (cl.toString());
			e = new Edge (CSource,CTarget,"SuperClass", null);
 			gh.ListEdge.add(e);
		}
	}
	//Parcourir toutes les classes disjointes du concept en question
	for (OWLClassExpression cl : cls.getDisjointClasses(ontology)){
	 	if (!(cl.isAnonymous())){
	 		CTarget = new Concept (cl.toString());
	 		e = new Edge (CSource,CTarget,"DisjointWith", null);
	 		e = new Edge (CTarget,CSource,"DisjointWith", null);
	 		gh.ListEdge.add(e);
	 	}
	}
	//Parcourir tous les individus appartenant au concept en question
	for (OWLIndividual ind : cls.getIndividuals(ontology)){
		if (!cls.isOWLThing())
			CTarget = new Concept (ind.toString());
			if (!gh.ListConcept.contains(CTarget))
				gh.ListConcept.add(CTarget);
 			e = new Edge (CSource,CTarget,"Attribution", null);
 			gh.ListEdge.add(e);
	}
	//Parcourir toutes les classes équivalentes au concept en question
	for (OWLClassExpression eq : cls.getEquivalentClasses(ontology)){
		
		if (!cls.isOWLThing()&&!(eq.isAnonymous())){
			CTarget = new Concept (eq.toString());
			//Il s'agit d'une subsomption dans les deux sens
			Edge e1 = new Edge (CSource,CTarget,"SubClass", null);
			Edge e2 = new Edge (CSource,CTarget,"SubClass", null);
			if (!gh.ListEdge.contains(e1))
				gh.ListEdge.add(e1);
			if (!gh.ListEdge.contains(e2))
				gh.ListEdge.add(e2);
		}
		else if (eq.isAnonymous())
			if (eq.getClassesInSignature().size()<=1){
			Restriction(CSource,eq, ontology, "EquivalentClasses");
		}
	}
	
}

return gh;
}


private Edge Restriction (Concept CSource, OWLClassExpression cls, OWLOntology ontology, String type){
	Edge e = null;
	RestrictionVisitor restrictionVisitor = new RestrictionVisitor(Collections.singleton(ontology));
	cls.accept(restrictionVisitor);
	Property prop = restrictionVisitor.getRestrictedPropertie();
	String tg = restrictionVisitor.getTarget();
	String InvProp = null;
	
	if (!(gh.ListProperty.contains(prop))&&(prop != null))
		gh.ListProperty.add(prop);
	if (prop!=null)
	{
		
		Concept CTarget= new Concept (tg);    
		e = new Edge (CSource,CTarget,"", prop);
		if (!(gh.ListEdge.contains(e)))
			gh.ListEdge.add(e);
		//Il s'agit de chercher la propriété inverse à partir de l'ontologie
		if (type == "EquivalentClasses"){
			OWLObjectPropertyExpression property=restrictionVisitor.getProp();
			for (OWLInverseObjectPropertiesAxiom pr : ontology.getInverseObjectPropertyAxioms(property)) {
	        	if (property.equals(pr.getFirstProperty()))
	        		InvProp=pr.getSecondProperty().toString();
	        	else InvProp=pr.getFirstProperty().toString();
					        	
	          }
			//Ajouter la propriété inverse, si elle existe, à la liste des propriétés
			if (InvProp!= null)
			{
				
				Property p = new Property (prop.getRestriction(), prop.getCardinality(),InvProp.toString());
				if (!(gh.ListProperty.contains(p)))
					gh.ListProperty.add(p);
				e = new Edge (CTarget,CSource,"", p);
				if (!(gh.ListEdge.contains(e)))
					gh.ListEdge.add(e);
			}
			
		}
	}


	return e;
}

private static class RestrictionVisitor extends OWLClassExpressionVisitorAdapter {

    private boolean processInherited = true;

    private Set<OWLClass> processedClasses;
    
    private Property restrictedPropertie;
    
    private String Target;
    
    private OWLObjectPropertyExpression prop;


    private Set<OWLOntology> onts;
    
   

    public RestrictionVisitor(Set<OWLOntology> onts) {
        
    	processedClasses = new HashSet<OWLClass>();
        this.onts = onts;
    }


    public void setProcessInherited(boolean processInherited) {
        this.processInherited = processInherited;
    }


    public Property getRestrictedPropertie() {
        return restrictedPropertie;
    }

    public String getTarget() {
        return Target;
    }

    public OWLObjectPropertyExpression getProp() {
        return prop;
    }

    
  public void reset() {
        processedClasses.clear();
        restrictedPropertie=null;
        Target="";
        prop=null;
    }
    
  public void visit(OWLObjectSomeValuesFrom desc) {
	    Property p = new Property ("MinCardinality", 1,desc.getProperty().toString());
	    Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
	    prop=desc.getProperty();
	    restrictedPropertie=p;
	    
	  
    }
  
  public void visit(OWLDataSomeValuesFrom desc) {
	    Property p = new Property ("MinCardinality", 1,desc.getProperty().toString());
	    Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
	    
      restrictedPropertie=p;
  	
  }
  
  public void visit(OWLObjectMinCardinality desc) {
    	Property p = new Property ("MinCardinality", desc.getCardinality(),desc.getProperty().toString());
    	Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
    	prop=desc.getProperty();
    	restrictedPropertie=p;
        
    }
  
  public void visit(OWLDataMinCardinality desc) {
  	Property p = new Property ("MinCardinality", desc.getCardinality(),desc.getProperty().toString());
  	Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
  	restrictedPropertie=p;
      
  }
    
    public void visit(OWLObjectMaxCardinality desc) {
    	Property p = new Property ("MaxCardinality", desc.getCardinality(),desc.getProperty().toString());
    	Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
    	prop=desc.getProperty();
    	restrictedPropertie=p;	        	
    }
    
    public void visit(OWLDataMaxCardinality desc) {
    	Property p = new Property ("MaxCardinality", desc.getCardinality(),desc.getProperty().toString());
    	Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
    	restrictedPropertie=p;	        	
    }
    
    public void visit(OWLObjectExactCardinality desc) {
    	
    	Property p = new Property ("ExactCardinality", desc.getCardinality(),desc.getProperty().toString());
    	Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
    	prop=desc.getProperty();
    	restrictedPropertie=p;
    	
    }
    
public void visit(OWLDataExactCardinality desc) {
    	
    	Property p = new Property ("ExactCardinality", desc.getCardinality(),desc.getProperty().toString());
    	Target = desc.toString().substring(desc.toString().lastIndexOf(" ")+1,desc.toString().length()-1);
    	restrictedPropertie=p;
    	
    }
    
    
}
}






